package com.lsh.rabbitmqutil;


import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;

import java.io.IOException;

/**
 * @author ：LiuShihao
 * @date ：Created in 2020/7/10 2:11 下午
 * @desc ：消息接收确认
 * 消息接收确认要比消息发送确认简单一点，因为只有一个消息回执（ack）的过程。
 * 使用@RabbitHandler注解标注的方法要增加 channel(信道)、message 两个参数。
 * 消费消息有三种回执方法
 */
@Slf4j
//@Component
public class ReceiverMessage1 {

    @RabbitHandler
    @RabbitListener(queues = "confirm_test_queue")
    public void processHandler(String msg, Channel channel, Message message) throws IOException {

        try {
            log.info("消费者收到消息：{}", msg);

            //TODO 具体业务
            int  a = 1/0;
            //basicAck：表示成功确认，使用此回执方法后，消息会被rabbitmq broker 删除。
            //deliveryTag：表示消息投递序号，每次消费消息或者消息重新投递后，deliveryTag都会增加。手动消息确认模式下，我们可以对指定deliveryTag的消息进行ack、nack、reject等操作。
            //multiple：是否批量确认，值为 true 则会一次性 ack所有小于当前消息 deliveryTag 的消息。
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);

        }  catch (Exception e) {

            if (message.getMessageProperties().getRedelivered()) {

                log.error("消息已重复处理失败,拒绝再次接收...");
                //basicReject：拒绝消息，与basicNack区别在于不能进行批量操作，其他用法很相似。
                //deliveryTag：表示消息投递序号。
                //requeue：值为 true 消息将重新入队列。
                channel.basicReject(message.getMessageProperties().getDeliveryTag(), false); // 拒绝消息
            } else {

                log.error("消息即将再次返回队列处理...");
                //basicNack ：表示失败确认，一般在消费消息业务异常时用到此方法，可以将消息重新投递入队列。
                //deliveryTag：表示消息投递序号。
                //multiple：是否批量确认。
                //requeue：值为 true 消息将重新入队列。
                channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, true);
            }
        }
    }
}

